/***************************************************************************
 *   Copyright (C) 2007 by Grzegorz Latarowski, Maciej Gajewski            *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/


#ifndef GNETTYPES_H
#define GNETTYPES_H

//---------------------------- includes --------------------------------------

#include <QtCore>




//------------------------ defines and constants -----------------------------

#define MKWORD( a ,b ,c ,d ) ( (a<<24) | (b<<16) | (c<<8) | d )
const quint32 gnet_magic =  MKWORD( 'g', 'n', 'e', 't' );
#define DEFAULT_MAGIC gnet_magic
#define QDATASTREAM_VERSION QDataStream::Qt_4_2




// ------------------------- GSerializableItem{} -----------------------------
/// Base interface class for all serializable items.
// ---------------------------------------------------------------------------
class GSerializableItem
{
public:
        /// Destructor
    virtual ~GSerializableItem() {}
    
        /// Writes item to the stream.
    virtual void write( QDataStream & out ) const = 0;
        /// Read item from synchronous stream. Need to be reimplemented
    virtual void read( QDataStream & in ) = 0;
    
    	/// Reads item from asynchronous device
    virtual void readFromSocket( QIODevice* pDevice, int timeout  ) = 0;
    	/// Writes item to asynchronous device
    virtual void writeToSocket( QIODevice* pDevice, int timeout  ) const = 0;
    
        /// Writes item to the device.
    void write( QIODevice * device ) const;
        /// Reads item from the device.
    void read( QIODevice * device );

    // connected stream operations
        /// \relates GSerializableItem
        /// Writes item \a item to the stream \a out and returns
        /// a reference to the stream.
    friend QDataStream & operator << ( QDataStream & out,
                                       const GSerializableItem & item );
        /// \relates GSerializableItem
        /// Reads item into \a item from the stream \a in and returns
        /// a reference to the stream.
    friend QDataStream & operator >> ( QDataStream & in,
                                       GSerializableItem & item );
 
    /// Reads QByteArray from asynchronous device.
    static void readBuffer( QIODevice* pDevice, QByteArray& buffer /* OUT */, int timeout );
    /// Writes QByteArray to asynchronous device.
    static void writeBuffer( QIODevice* pDevice, const QByteArray& buffer, int timeout );
    
}; // class !GSerializableItem
// ---------------------------------------------------------------------------



// ---------------------------- GHeader{} ------------------------------------
/// Represents packets header.
// ---------------------------------------------------------------------------
class GHeader : public QObject, public GSerializableItem
{
Q_OBJECT;

public:
        /// \brief Constructs the header.
        ///
        /// Sets _type to \type and copies \a parent to GSerializableItem constructor.
    GHeader( quint64 type = 0,
             QObject * parent = 0 )
    : QObject( parent ), GSerializableItem(), _type( type ) {}
        /// Copy constructor
    GHeader( const GHeader & header );

        /// Returns type of the object the header belongs to.
    quint64 type() const { return _type; }
        /// \brief Returns string info about header.
        ///
        /// Creates string with field values.
    QString info() const;
    
        /// Copies \a header to this object.
    GHeader & operator = ( GHeader & header );
    
        /// \brief Writes item to the \a device.
        ///
        /// \a version is provided for futured compatibility.
    void write( QDataStream & out ) const;
        /// \brief Read item from the \a device.
        ///
        /// \a version is provided for futured compatibility.
    void read( QDataStream & in );
    
    	/// Reads header from asynchronous device
    virtual void readFromSocket( QIODevice* pDevice, int timeout  );
    	/// Writes item to asynchronous device
    virtual void writeToSocket( QIODevice* pDevice, int timeout  ) const;
    
        /// Sets type of the packet to \a type.
    void setType( const quint64 type ) { _type = type; }

private:
        /// Writes headers data to the out stream
    virtual void writeData( QDataStream & out ) const;
        /// Reads headers data from the in stream 
    virtual void readData( QDataStream& in );
        
        /// Defines type of the object the header belongs to.
        /// Initiated as 0 (GPacket::NotSet).
    quint64 _type;

}; // class !GHeader
// ---------------------------------------------------------------------------



// ---------------------------- GPacket{} ------------------------------------
/// \class GPacket
/// \brief Its a base class for every class used in network communication.
///
/// Every other class, that need to be transmitted into network, need to
/// inherit GPacket. All that you need to implement is writeData()
/// and readData() custom data fields into i/o stream.
// ---------------------------------------------------------------------------
class GPacket : public QObject, public GSerializableItem
{
public:
        /// \brief Creates packet.
        /// 
        /// Copies \a parent to GSerializableItem constructor. 
        /// Sets _header \a type and \a parent.
    GPacket( qint32 type = 0,
             QObject * parent = 0 )
    : QObject( parent ), GSerializableItem(), _header( type, parent ) {}
    
        /// Returns header appropiate for the packet
    virtual GHeader header() const  { return _header; }
        /// Returns type of the packet
    qint32 type() { return header().type(); }
    
        /// \brief Returns string info about packet.
        ///
        /// Creates string with field values.
    virtual QString info() { return QString(header().info() + "GPacket"); }
    
        /// Writes packet to the stream \a out.
    void write( QDataStream & out ) const;
        /// Reads packet from the stream \a in.
    void read( QDataStream & in );
    
    	/// Reads packet from asynchronous device
    virtual void readFromSocket( QIODevice* pDevice, int timeout );
    	/// Writes item to asynchronous device
    virtual void writeToSocket( QIODevice* pDevice, int timeout  ) const;
    
        /// Sets packets header to \a header.
    void setHeader( GHeader & header ) { _header = header; }
        /// Set packets type to  \a type.
    void setType( qint32 type ) { _header.setType( type ); }
    
private:
    	/// Writes packet data to stream 
    virtual void writeData( QDataStream & out ) const = 0;
    	/// Reads packet data from data stream 
    virtual void readData( QDataStream & in ) = 0;
            
    GHeader _header;        ///< Packets header.
    
}; // class !GPacket
// ---------------------------------------------------------------------------




#endif // !GNETTYPES_H




// eof
